/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * File Name          : freertos.c
 * Description        : Code for freertos applications
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2023 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include "stdlib.h"
#include "usart.h"
#include "ctrl.h"
#include "dht11.h"
#include "air780e.h"
#include "oled.h"
#include "menu.h"
#include "tim.h"
#include "mutex.h"
#include "log.h"
#include "iwdg.h"

static char *TAG = "freertos";
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

u8g2_t u8g2; /*定义u8g2结构体*/

#define RX_BUFFER_SIZE 256
char rx_buffer2[RX_BUFFER_SIZE]; /*数据缓存区*/
uint8_t rx_index2 = 0;           /*存储接收数据长度*/

dht_t dht_data = {GPIOA, GPIO_PIN_15, 0, 0};                                 /* 温湿度结构体数据 */
ctrl_t device = {GPIOB, GPIOB, GPIO_PIN_8, GPIO_PIN_9, 255, 255, 255, true}; /* 控制设备结构体 */
air780e_t air780e;                                                           /* air780e结构体标志 */
menu_threshold_t menu_temp_threshold = {27.0};                               /* 菜单设置阈值结构体--默认27° */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
/* Definitions for guitTask */
osThreadId_t guitTaskHandle;
const osThreadAttr_t guitTask_attributes = {
    .name = "guitTask",
    .stack_size = 128 * 4,
    .priority = (osPriority_t)osPriorityLow,
};
/* Definitions for dhtTask */
osThreadId_t dhtTaskHandle;
const osThreadAttr_t dhtTask_attributes = {
    .name = "dhtTask",
    .stack_size = 128 * 4,
    .priority = (osPriority_t)osPriorityLow1,
};
/* Definitions for uartTask */
osThreadId_t uartTaskHandle;
const osThreadAttr_t uartTask_attributes = {
    .name = "uartTask",
    .stack_size = 128 * 4,
    .priority = (osPriority_t)osPriorityLow2,
};

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/**
 * @brief HAL_UART_RxCpltCallback
 * @note  -- USART1接收完成回调函数
 * @param huart
 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    /* 串口中断并不在操作系统任务范畴里面,所以这里就不用MY_LOG进行日志打印,况且共享资源只是缓冲区也只在这个中断里面使用,不用担心会锁住 */
    if (huart->Instance == USART2) /* 串口2回调 */
    {
        /* 接收完成，保存数据到缓冲区 */
        rx_buffer2[rx_index2++] = huart->Instance->DR;

        if (rx_index2 < 248) /* 避免数组越界 */
        {
            /* 如果接收到"OK"返回结束符，打印并清空缓冲区 */
            if ((rx_buffer2[rx_index2 - 2] == 'O' && rx_buffer2[rx_index2 - 1] == 'K')) // 数据处理 换行结束，可以根据实际需求更改条件
            {
                if (strstr(rx_buffer2, "+CMGS") != NULL) /*发送成功反馈*/
                {
                    printf("clear send dht11 sms flag\r\n\r\n");
                    air780e.send_flag = 0; /* 清除air780e发送标志位 */
                }
                printf("%s\r\n", rx_buffer2);
                memset(rx_buffer2, 0, sizeof(rx_buffer2));
                rx_index2 = 0;
            }
        }
        else
        {
            printf("\r\nThe buffer is full! Start clear!\r\n\r\n");
            memset(rx_buffer2, 0, sizeof(rx_buffer2));
            rx_index2 = 0;
        }

        /* 继续接收数据 */
        HAL_UART_Receive_IT(&huart2, (uint8_t *)(rx_buffer2 + rx_index2), 1);
    }
}

// /**
//  * @brief HAL_GPIO_EXTI_Callback
//  *
//  * @param GPIO_Pin
//  */
// void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
// {
//     uint32_t debounce_time = 50;                     // 延时时间，单位为毫秒
//     static uint32_t last_interrupt_time = 0;         // 上一次中断时间
//     uint32_t current_interrupt_time = HAL_GetTick(); // 当前中断时间
//     // 判断是否满足延时条件->消抖
//     if ((current_interrupt_time - last_interrupt_time) > debounce_time)
//     {
//         // 处理按键中断事件
//         if (GPIO_Pin == GPIO_PIN_4)
//         {
//             if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET)
//             {
//                 printf("GPIO_PIN_4\r\n"); // 处理事件
//             }
//             __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);
//         }
//         else if (GPIO_Pin == GPIO_PIN_5)
//         {
//             if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_RESET)
//             {
//                 printf("GPIO_PIN_5\r\n");
//             }
//             __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_5);
//         }
//         else if (GPIO_Pin == GPIO_PIN_6)
//         {
//             if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == GPIO_PIN_RESET)
//             {
//                 printf("GPIO_PIN_6\r\n");
//             }
//             __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_6);
//         }
//     }
//     // 更新上一次中断时间
//     last_interrupt_time = current_interrupt_time;
// }

/* USER CODE END FunctionPrototypes */

void StartGuiTask(void *argument);
void StartSensorTask(void *argument);
void StartUartTask(void *argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/**
 * @brief  FreeRTOS initialization
 * @param  None
 * @retval None
 */
void MX_FREERTOS_Init(void)
{
    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* USER CODE BEGIN RTOS_MUTEX */
    /* add mutexes, ... */
    create_mutex(); /*创建互斥锁*/
    /* USER CODE END RTOS_MUTEX */

    /* USER CODE BEGIN RTOS_SEMAPHORES */
    /* add semaphores, ... */
    /* USER CODE END RTOS_SEMAPHORES */

    /* USER CODE BEGIN RTOS_TIMERS */
    /* start timers, add new ones, ... */
    /* USER CODE END RTOS_TIMERS */

    /* USER CODE BEGIN RTOS_QUEUES */
    /* add queues, ... */
    /* USER CODE END RTOS_QUEUES */

    /* Create the thread(s) */
    /* creation of guitTask */
    guitTaskHandle = osThreadNew(StartGuiTask, NULL, &guitTask_attributes);

    /* creation of dhtTask */
    dhtTaskHandle = osThreadNew(StartSensorTask, NULL, &dhtTask_attributes);

    /* creation of uartTask */
    uartTaskHandle = osThreadNew(StartUartTask, NULL, &uartTask_attributes);

    /* USER CODE BEGIN RTOS_THREADS */
    /* add threads, ... */
    /* USER CODE END RTOS_THREADS */

    /* USER CODE BEGIN RTOS_EVENTS */
    /* add events, ... */
    /* USER CODE END RTOS_EVENTS */
}

/* USER CODE BEGIN Header_StartGuiTask */
/**
 * @brief  Function implementing the guitTask thread.
 * @param  argument: Not used
 * @retval None
 */
/* USER CODE END Header_StartGuiTask */
void StartGuiTask(void *argument)
{
    /* USER CODE BEGIN StartGuiTask */

    TickType_t xLastWakeTime = xTaskGetTickCount(); /*第一次运行时获取当前系统时间*/

    u8g2Init(&u8g2);                                /* 初始化u8g2 */
    u8g2_SetFont(&u8g2, u8g2_font_wqy12_t_gb2312b); /* 设置u8g2字体 */
    u8g2_ClearBuffer(&u8g2);                        /* 清除缓冲区 */
    MY_LOGI(TAG, "gui task init!\r\n");             /* MY_LOG */
    menu_init(&u8g2);                               /* 菜单初始化 */

    /* Infinite loop */
    for (;;)
    {
        key_scan();                                        /* 按键扫描 */
        ui_proc(&u8g2, &dht_data, &menu_temp_threshold);   /* UI进程 -- 温湿度数据和阈值设置数据 */
        vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(5)); /* 每次运行时延迟 5ms，以确保任务能够及时释放 CPU 资源 */
    }
    /* USER CODE END StartGuiTask */
}

/* USER CODE BEGIN Header_StartSensorTask */
/**
 * @brief Function implementing the dhtTask thread.
 * @param argument: Not used
 * @retval None
 */
/* USER CODE END Header_StartSensorTask */
void StartSensorTask(void *argument)
{
    /* USER CODE BEGIN StartSensorTask */

    TickType_t xLastWakeTime = xTaskGetTickCount(); /*第一次运行时获取当前系统时间*/

    /* Infinite loop */
    for (;;)
    {
        HAL_IWDG_Refresh(&hiwdg);                                                   /* 喂狗 */
        xSemaphoreTake(dht_mutex, portMAX_DELAY);                                   /* 获取dht温湿度的互斥锁 */
        DHT11_Read_Temperature_Humidity(&dht_data);                                 /* 获取dht11温湿度数据 访问共享资源-dht温湿度*/
        xSemaphoreGive(dht_mutex);                                                  /* 释放互斥锁 */
        MY_LOGI(TAG, "temp: %.1fC humi: %.1f%%\r\n", dht_data.temp, dht_data.humi); /* 串口打印温湿度数据 */
        vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1000));                       /* 每次运行时延迟 1000ms，以确保任务能够及时释放 CPU 资源 */
    }
    /* USER CODE END StartSensorTask */
}

/* USER CODE BEGIN Header_StartUartTask */
/**
 * @brief Function implementing the uartTask thread.
 * @param argument: Not used
 * @retval None
 */
/* USER CODE END Header_StartUartTask */
void StartUartTask(void *argument)
{
    /* USER CODE BEGIN StartUartTask */

    TickType_t xLastWakeTime = xTaskGetTickCount(); /*第一次运行时获取当前系统时间*/

    HAL_UART_Receive_IT(&huart2, (uint8_t *)(rx_buffer2 + rx_index2), 1); /* 使能USART2接收中断 */
    MY_LOGI(TAG, "uart task init!\r\n");                                  /* MY_LOGI */
    air780e_init();                                                       /* 配置air780e */
    ctrl_init(&device);                                                   /* 初始化控制和反馈脚 */

    /* Infinite loop */
    for (;;)
    {
        MY_LOGI(TAG, "rx_buffer2 = %d /// rx_index2 = %d\r\n", strlen(rx_buffer2), rx_index2); /* 查看串口缓冲区大小 */
        usart2_proc(rx_buffer2, &rx_index2, &air780e, &device);                                /* 短信接收处理 */
        xSemaphoreTake(dht_mutex, portMAX_DELAY);                                              /* 获取dht温湿度的互斥锁 */
        send_dht_sms_app(&dht_data, &air780e);                                                 /* 短信发送温湿度 */
        ctrl_proc(&device, &dht_data, &menu_temp_threshold);                                   /* 控制进程 */
        xSemaphoreGive(dht_mutex);                                                             /* 释放互斥锁 */
        vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(2000));                                  /* 每次运行时延迟 2000ms，以确保任务能够及时释放 CPU 资源 */
    }
    /* USER CODE END StartUartTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */
